package com.apes.fn.scm.retailOrder.service.expense;

import com.alibaba.fastjson.JSONObject;
import com.apes.fn.fico.settleExpense.SettleExpense;
import com.apes.fn.fico.settleExpense.SettleExpenseRepository;
import com.apes.fn.scm.retailOrder.service.RetailOrderFnExpenseOrderService;
import com.apes.fn.scm.settleCheck.model.PartnerCheck;
import com.apes.fn.scm.settleCheck.model.PartnerCheckItem;
import com.apes.fn.scm.settleCheck.reponsitory.PartnerCheckRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.util.LogicalUtil;
import com.apes.framework.util.MapUtil;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.party.model.PartyRole;
import lombok.Data;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 零售单生成结算费用抽象类
 *
 * @author wuq
 * @create 2020-04-20 15:57
 */
@Data
public abstract class AbstractRetailOrderFnExpense {

    private double amount;              // 销售金额
    private String origin;              // 原单据
    private String originBusinessType;  // 原单据类型
    private String source;              // 来源单据
    private String sourceBusinessType;  // 来源单据类型

    private String carLicense;
    private Enumeration caseType;

    AbstractRetailOrderFnExpense(double amount, String origin, String originBusinessType, String source,
                                 String sourceBusinessType, String carLicense, Enumeration caseType) {
        this.amount = amount;
        this.origin = origin;
        this.originBusinessType = originBusinessType;
        this.source = source;
        this.sourceBusinessType = sourceBusinessType;
        this.carLicense = carLicense;
        this.caseType = caseType;
    }

    public abstract void create(JSONObject condition);     // 总入口方法

    public abstract void createPlatformExpense(double expense);                     // 创建平台费

    public abstract void createInfoExpense(double expense);           // 创建信息费

    public abstract void createLossQuotationExpense(double expense);  // 创建定损费

    /**
     * 注：已经使用获取条件策略获取，此方法作废
     * 获取赋能费用算法
     *
     * @param company 公司
     * @return 赋能费用算法(平台服务费算法)
     */
    @Deprecated
    PartnerCheckItem getPartnerCheckItem(PartyRole company) {
        List<Map> rows = new ArrayList();
        rows.add(MapUtil.mapper("field", "state", "operator", "EQ", "value", "approve"));
        rows.add(MapUtil.mapper("field", "endDate", "operator", "GTE", "value", new Date()));
        rows.add(MapUtil.mapper("field", "startDate", "operator", "LTE", "value", new Date()));
        rows.add(MapUtil.mapper("field", "fnCustomer.id", "operator", "EQ", "value", company.getId()));
        PartnerCheck partnerCheck = SpringManager.getBean(PartnerCheckRepository.class).findAll(JpaDsl.toCriteria(rows)).stream()
                .findFirst().orElseThrow(() -> new RuntimeException("未找到有效的赋能商户政策, 公司编码: " + company.getId()));

        return partnerCheck.getPartnerCheckItems().stream().filter(item -> "A09".equals(item.getExpenseType().getId())).findFirst()
                .orElseThrow(() -> new RuntimeException("未定义赋能商户政策中的平台服务费， 公司编码: " + company.getId()));
    }

    /**
     * 获取平台服务费
     *
     * @param company
     * @return
     */
    double getPlatformFreeRatio(PartyRole company) {
        double ratio = SpringManager.getBean(RetailOrderFnExpenseOrderService.class).getPlatformFreeRatio(company);
        return ratio;
    }

    /**
     * 判断案件类型
     *
     * @param caseType 枚举值
     * @return 返回对应的类型
     */
    String getCaseType(String caseType) {
        if (ExpenseEnum.carAccidentVipPush.getCode().equals(caseType) || ExpenseEnum.carAccidentStore.getCode().equals(caseType)) {
            return "push";
        } else if (ExpenseEnum.carAccidentVip.getCode().equals(caseType)) {
            return "code";
        } else if (ExpenseEnum.notCarAccidentVipStore.getCode().equals(caseType) || ExpenseEnum.notCarAccidentVipBusiness.getCode().equals(caseType)
                || ExpenseEnum.redBullAccidentStore.getCode().equals(caseType)) {
            return "notCode";
        } else {
            return "";
        }
    }

    /**
     * 生费用单
     *
     * @param tenant      公司
     * @param payment     收/付款方
     * @param expenseAmt  费用金额
     * @param expenseType 费用类型
     * @param inDept      收入门店
     * @param outDept     支出门店
     * @param remark      备注
     */
    void createExpense(PartyRole tenant, PartyRole payment, double expenseAmt, String expenseType, Dept inDept, Dept outDept, String remark) {
        if (expenseAmt < 0.0001d) return;
        SettleExpense inSettleExpense = createSettleExpense(tenant, payment, expenseAmt, "in", expenseType, inDept, remark);
        saveSettleExpense(inSettleExpense);
        SettleExpense outSettleExpense = createSettleExpense(payment, tenant, expenseAmt, "out", expenseType, outDept, remark);
        saveSettleExpense(outSettleExpense);
    }

    /**
     * 生费用单，添加额外字段
     *
     * @param tenant         公司
     * @param payment        收/付款方
     * @param expenseAmt     费用金额
     * @param expenseType    费用类型
     * @param inDept         收入门店
     * @param outDept        支出门店
     * @param remark         备注
     * @param backType       返还类型
     * @param platformReturn 平台返还标记
     */
    void createExpenseAdditionField(PartyRole tenant, PartyRole payment, double expenseAmt, String expenseType, Dept inDept, Dept outDept, String remark,
                                    String backType, int platformReturn) {
        if (expenseAmt < 0.0001d) return;
        SettleExpense inSettleExpense = createSettleExpense(tenant, payment, expenseAmt, "in", expenseType, inDept, remark);
        inSettleExpense.setBackType(backType);
        inSettleExpense.setPlatformReturn(platformReturn);
        saveSettleExpense(inSettleExpense);

        SettleExpense outSettleExpense = createSettleExpense(payment, tenant, expenseAmt, "out", expenseType, outDept, remark);
        outSettleExpense.setBackType(backType);
        outSettleExpense.setPlatformReturn(platformReturn);
        saveSettleExpense(outSettleExpense);
    }


    /**
     * 生费用单
     *
     * @param tenant      公司
     * @param payment     收/付款公司
     * @param expenseAmt  费用金额
     * @param type        类型（收入或者支出）
     * @param expenseType 费用类型
     * @return SettleExpense
     */
    SettleExpense createSettleExpense(PartyRole tenant, PartyRole payment, double expenseAmt, String type, String expenseType, Dept dept, String remark) {
        double amt = payment.getParty().getCorporate().getCurrency().round(expenseAmt);
        if (expenseAmt < 0.0001d) return null;

        SettleExpense settleExpense = new SettleExpense();
        settleExpense.setTenant(tenant);
        settleExpense.setPayment(payment);
        settleExpense.setAmount(amt);        // 费用金额
        settleExpense.setType(type);
        settleExpense.setExpenseType(expenseType);
        settleExpense.setDept(dept);
        settleExpense.setRemark(remark);

        settleExpense.setLossQuotationAmt(amount);  // 定损金额
        settleExpense.setCarLicense(carLicense);
        settleExpense.setCaseType(caseType);
        settleExpense.setOrigin(origin);
        settleExpense.setOriginBusinessType(originBusinessType);
        settleExpense.setSource(source);
        settleExpense.setSourceBusinessType(sourceBusinessType);
        return settleExpense;
    }

    SettleExpense saveSettleExpense(SettleExpense settleExpense) {
        SettleExpense newSettleExpense = SpringManager.getBean(SettleExpenseRepository.class).saveAndFlush(settleExpense);
        if(!"in".equals(settleExpense.getType())){
            saveIncome(newSettleExpense);   //  创建费用账单
        }
        return newSettleExpense;
    }

    private void saveIncome(SettleExpense settleExpense) {
        if (LogicalUtil.in(settleExpense.getExpenseType(), "platformExpense", "innerInfoExpense", "insuranceDiscountExpense")) return;

        Map m = MapUtil.mapper("expenseType", "insuranceCrossDiscountExpense".equals(settleExpense.getExpenseType()) ? "A13" :
                        "infoExpense".equals(settleExpense.getExpenseType()) ? "F001" : "lossQuotationExpense".equals(settleExpense.getExpenseType()) ? "F002":settleExpense.getExpenseType(),
                "source", settleExpense.getId(), "sourceBusinessType", "SettleIncome",
                "originBusinessType", settleExpense.getOriginBusinessType(), "creator", "system",
                "company", settleExpense.getPayment().getId(),
                "reconcileBeginDate", settleExpense.getCreateDate(), "reconcileEndDate", settleExpense.getCreateDate(),
                "amount", settleExpense.getAmount(), "note", settleExpense.getRemark(),"remark","平台定损！",
                "carLicense", settleExpense.getCarLicense());
/*
        if ("in".equals(settleExpense.getType())) {
            //收入生成费用账单
            m.put("partner", settleExpense.getTenant().getParty().getPartyRoleByType("Supplier").getId());
            m.put("deptId", settleExpense.getDept().getId());
        } else {*/
        //支出生成费用账单
        m.put("partner", settleExpense.getTenant().getParty().getPartyRoleByType("Customer").getId());
        m.put("deptId", settleExpense.getDept().getId());
        /* }*/

        SpringManager.getBean(DomainService.class).invoke("income.incomeCreate", m);
    }

}
